package shapes.shapes2D.polygon 
{
	import flash.display.Graphics;
	import flash.geom.Point;
	import utils.GeomUtils;
	/**
	 * @author Nicolas Barradeau
	 * http://en.nicoptere.net
	 */
	public final class Edge
	{
		private var _p0:Point;
		private var _p1:Point;
		private var _id:int;
		private var _next:Edge;
		private var _prev:Edge;
		private var _angle:Number;
		private var _length:Number;
		private var _normalLength:Number = 10;
		
		public function Edge( p0:Point, p1:Point, id:int = -1 ) 
		{
			
			this.p0 = p0;
			this.p1 = p1;
			this.id = id;
			
			_angle = GeomUtils.angle( p0, p1 );
			_length = GeomUtils.distance( p0, p1 );
			
		}
		
		public function isLeft( p:Point ):Boolean
		{
			var a:Number = GeomUtils.distance(p, p0.add(Point.polar(1, Math.atan2(p0.y - p1.y, p0.x - p1.x) + Math.PI / 2)));
			
			var b:Number = GeomUtils.distance(p, p0.add(Point.polar( -1, Math.atan2(p0.y - p1.y, p0.x - p1.x) + Math.PI / 2)));
			
			return a < b;
		}
		
		public function intersect( e:Edge, asSegment0:Boolean = true, asSegment1:Boolean = true ):Point
		{
			
			return Intersection.lineIntersectLine( p0, p1, e.p0, e.p1, asSegment0, asSegment1 );
			
		}
		
		public function equals( e:Edge, sameDirection:Boolean = true ):Boolean
		{
			if ( sameDirection ) return p0.equals( e.p0 ) && p1.equals( e.p1 );
			
			return ( ( p0 == e.p0 && p1 == e.p1 ) || ( p0 == e.p1 && p1 == e.p0 ) );
		}
		
		/**
		 * 
		 * @param	e the edge to merge
		 * @param	dir -1 : 1 specifies which point should swap : 1 -> edge.p1 = other.p1 | -1 edge.p0 = other.p0
		 */
		public function merge( e:Edge, dir:int = 1 ):void 
		{	
			if ( dir > 0 ) 
			{
				p1 = e.p1;
			}
			else
			{
				p0 = e.p0;
			}
		}
		
		public function pointAt( t:Number ):Point
		{
			return new Point(	p0.x + Math.cos( angle ) * length * t, 
								p0.y + Math.sin( angle ) * length * t 	);
		}
		
		public function get center():Point
		{
			return new Point( p0.x + width * .5, p0.y + height * .5);
		}
		
		public function get angle():Number 
		{ 
			return GeomUtils.angle( p0, p1 ); 
		}
		
		public function get squareLength():Number
		{ 
			return GeomUtils.squareDistance( p0.x, p0.y, p1.x, p1.y ); 
		}
		
		public function get length():Number
		{ 
			return GeomUtils.distance( p0, p1 ); 
		}
		
		public function get width():Number 
		{	
			return p1.x - p0.x;		
		}
		public function get height():Number 
		{	
			return p1.y - p0.y;		
		}
		
		
		public function get p0():Point { return _p0; }
		
		public function set p0(value:Point):void 
		{
			_p0 = value;
		}
		
		public function get p1():Point { return _p1; }
		
		public function set p1(value:Point):void 
		{
			_p1 = value;
		}
		
		public function get id():int { return _id; }
		
		public function set id(value:int):void 
		{
			_id = value;
		}
		
		public function get next():Edge { return _next; }
		
		public function set next(value:Edge):void 
		{
			_next = value;
		}
		
		public function get prev():Edge { return _prev; }
		
		public function set prev(value:Edge):void 
		{
			_prev = value;
		}
		
		public function draw( graphics:Graphics = null ):void 
		{ 
			graphics.moveTo( p0.x, p0.y );
			graphics.lineTo( p1.x, p1.y );
		}
		
		public function get leftNormal():Edge
		{ 
			var a:Number = angle - Math.PI * .5;
			return new Edge( p0, new Point( 	p0.x + Math.cos( a ) * _normalLength,
												p0.y + Math.sin( a ) * _normalLength ) );
		}
		
		public function get rightNormal():Edge
		{ 
			var a:Number = angle + Math.PI * .5;
			return new Edge( p0, new Point( 	p0.x + Math.cos( a ) * _normalLength,
												p0.y + Math.sin( a ) * _normalLength ) );
		}
		
		public function get normalLength():Number { return _normalLength; }
		
		public function set normalLength(value:Number):void 
		{
			_normalLength = value;
		}
		
		
		public function determinant( p:Point ):Number
		{
			return ( ( p0.x-p1.x )*( p.y - p1.y ) ) - ( ( p.x-p1.x )*( p0.y-p1.y ) );
		}
		
	}

}